package com.jason.common.file.word.resolver;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.jason.common.file.word.dto.WordImportQuestionData;
import com.jason.common.file.word.dto.WordTemplateTreeNode;
import com.jason.common.file.word.exception.WordImportException;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * 默认Word文档Text文本解析器
 *
 * @author guozhongcheng
 * @since 2023/10/8
 **/
@Slf4j
public class DefaultWordTextResolver implements WordTextResolverInterface {
    /**
     * 选项字母数组
     */
    private static final String[] OPTION_LETTER_ARR = {"\nA.", "\nB.", "\nC.", "\nD.", "\nE.", "\nF.", "\nG.", "\nH."};

    /**
     * 当前正在解析的文本
     */
    private String currSubText = "";
    /**
     * 当前解析的试卷名称
     */
    private String currPaperName;
    /**
     * 当前解析的试卷小节名称
     */
    private String currPaperTitleName;
    /**
     * 当前解析的试题类型枚举
     */
    private QuestionTypeEnum currQuestionTypeEnum;
    /**
     * 当前解析的试题背景资料
     */
    private String currQuestionTitleSplitterValue;
    /**
     * 当前解析的试题选项列表
     */
    private List<WordImportQuestionData.OptionData> currOptionDataList;

    /**
     * 试题数据列表
     */
    private final List<WordImportQuestionData> LIST = new ArrayList<>(16);
    /**
     * 排序
     */
    private int sort = 0;

    public List<WordImportQuestionData> getResultList() {
        return this.LIST;
    }

    @Override
    public List<WordImportQuestionData> parse(String wordTextStr, List<WordTemplateTreeNode> templateTreeNodeList) {
        try {
            this.currSubText = wordTextStr;
            for (WordTemplateTreeNode templateTreeNode : templateTreeNodeList) {
                String nodeName = templateTreeNode.getNodeName();
                int index = wordTextStr.indexOf(nodeName);
                if (index != -1) {
                    templateTreeNode.setIndexOf(index);
                }
            }
            // 降序
            templateTreeNodeList = templateTreeNodeList.stream().filter(n -> n.getIndexOf() != -1)
                    .sorted(Comparator.comparing(WordTemplateTreeNode::getIndexOf).reversed()).collect(Collectors.toList());
            if (CollUtil.isEmpty(templateTreeNodeList)) {
                throw new IllegalArgumentException("缺少试卷名称节点信息");
            }
            // 解析试卷数据
            this.doParsePaperData(wordTextStr, templateTreeNodeList);
        } catch (Exception e) {
            if (e instanceof IllegalArgumentException) {
                throw new WordImportException(e.getMessage(), this.currSubText);
            }
            throw new WordImportException("发生未知错误: " + e.getMessage(), this.currSubText, e);
        }
        return this.LIST;
    }

    @Override
    public List<WordImportQuestionData> concurrentParse(String wordTextStr, List<WordTemplateTreeNode> templateTreeNodeList, ThreadPoolExecutor threadPoolExecutor) {
        return this.parse(wordTextStr, templateTreeNodeList);
    }

    /**
     * 执行解析试卷数据逻辑
     *
     * @param wordTextStr          试卷文本字符串
     * @param templateTreeNodeList 模板树节点列表
     */
    private void doParsePaperData(String wordTextStr, List<WordTemplateTreeNode> templateTreeNodeList) {
        int endIndex = -1;
        for (WordTemplateTreeNode treeNode : templateTreeNodeList) {
            // 构建试题目录结构
            int indexOf = treeNode.getIndexOf();
            String nodeName = treeNode.getNodeName();
            if (endIndex == -1) {
                endIndex = wordTextStr.length();
            }
            int beginIndex = indexOf + nodeName.length();
            String subText = StrUtil.sub(wordTextStr, beginIndex, endIndex);
            treeNode.setBeginIndex(beginIndex);
            treeNode.setEndIndex(endIndex);
            treeNode.setSubText(subText);

            if (StrUtil.isBlank(subText)) {
                continue;
            }
            if (CollUtil.isEmpty(treeNode.getChildrenList())) {
                throw new IllegalArgumentException("模板对象中缺失小节或大题");
            }
            // 解析试卷小节数据
            this.doParsePaperTitleData(treeNode);
            endIndex = beginIndex - nodeName.length();
        }
    }

    /**
     * 并发执行解析试卷小节数据
     *
     * @param treeNode 树节点
     */
    public void concurrentDoParsePaperTitleData(WordTemplateTreeNode treeNode) {
        try {
            this.doParsePaperTitleData(treeNode);
        } catch (Exception e) {
            if (e instanceof IllegalArgumentException) {
                throw new WordImportException(e.getMessage(), this.currSubText);
            }
            throw new WordImportException("发生未知文本解析错误: " + e.getMessage(), this.currSubText, e);
        }
    }

    /**
     * 执行解析试卷小节数据
     *
     * @param treeNode 树节点
     */
    private void doParsePaperTitleData(WordTemplateTreeNode treeNode) {
        String paperSubText = treeNode.getSubText();
        this.currSubText = paperSubText;
        List<WordTemplateTreeNode> childrenList = treeNode.getChildrenList();
        for (WordTemplateTreeNode templateTreeNode : childrenList) {
            String nodeName = templateTreeNode.getNodeName();
            int index = paperSubText.indexOf(nodeName);
            if (index != -1) {
                templateTreeNode.setIndexOf(index);
            }
        }
        // 降序
        List<WordTemplateTreeNode> paperTitleTreeNodeList = childrenList.stream().filter(n -> n.getIndexOf() != -1)
                .sorted(Comparator.comparing(WordTemplateTreeNode::getIndexOf).reversed()).collect(Collectors.toList());
        Assert.notEmpty(paperTitleTreeNodeList, "缺少试卷小节名称节点信息, 节点标识符:{}"
                , StrUtil.join("|", childrenList.stream().map(WordTemplateTreeNode::getNodeName).collect(Collectors.toList())));

        // 赋值试卷名称信息
        int nearNodeNameIndexOf = paperTitleTreeNodeList.get(paperTitleTreeNodeList.size() - 1).getIndexOf();
        if (nearNodeNameIndexOf == 0) {
            throw new IllegalArgumentException("缺少试卷名称");
        }
        String paperName = paperSubText.substring(0, nearNodeNameIndexOf);
        Assert.notBlank(paperName, "解析试卷名称为空");
        // 清洗数据，移除换行符和首尾的空格
        String cleanPaperName = this.cleanTextData(paperName);
        treeNode.setNodeValue(cleanPaperName);
        this.currPaperName = cleanPaperName;

        int endIndex = -1;
        for (WordTemplateTreeNode templateTreeNode : paperTitleTreeNodeList) {
            // 构建试题小节目录结构
            int indexOf = templateTreeNode.getIndexOf();
            String nodeName = templateTreeNode.getNodeName();
            if (endIndex == -1) {
                endIndex = paperSubText.length();
            }
            int beginIndex = indexOf + nodeName.length();
            String subText = StrUtil.sub(paperSubText, beginIndex, endIndex);
            templateTreeNode.setBeginIndex(beginIndex);
            templateTreeNode.setEndIndex(endIndex);
            templateTreeNode.setSubText(subText);

            if (StrUtil.isBlank(subText)) {
                continue;
            }
            if (CollUtil.isEmpty(templateTreeNode.getChildrenList())) {
                throw new IllegalArgumentException("试卷下缺失小节或大题");
            }
            // 解析试卷小节数据
            this.doParseQuestionTypeData(templateTreeNode);
            endIndex = beginIndex - nodeName.length();
        }
    }

    /**
     * 构建试题类型数据
     *
     * @param treeNode 树节点
     */
    private void doParseQuestionTypeData(WordTemplateTreeNode treeNode) {
        String allQuestionSubText = treeNode.getSubText();
        this.currSubText = allQuestionSubText;
        List<WordTemplateTreeNode> childrenList = treeNode.getChildrenList();
        for (WordTemplateTreeNode templateTreeNode : childrenList) {
            String nodeName = templateTreeNode.getNodeName();
            int index = allQuestionSubText.indexOf(nodeName);
            if (index != -1) {
                templateTreeNode.setIndexOf(index);
            }
        }

        // 降序
        List<WordTemplateTreeNode> questionTypeTreeNodeList = childrenList.stream().filter(n -> n.getIndexOf() != -1)
                .sorted(Comparator.comparing(WordTemplateTreeNode::getIndexOf).reversed()).collect(Collectors.toList());
        Assert.notEmpty(questionTypeTreeNodeList, "缺少试卷试题分类名称节点信息，节点标识符:{}",
                StrUtil.join("|", childrenList.stream().map(WordTemplateTreeNode::getNodeName).collect(Collectors.toList())));
        // 赋值试卷小节名称信息
        int nearNodeNameIndexOf = questionTypeTreeNodeList.get(questionTypeTreeNodeList.size() - 1).getIndexOf();
        if (nearNodeNameIndexOf == 0) {
            throw new IllegalArgumentException("缺少小节名称");
        }
        String paperTitleName = allQuestionSubText.substring(0, nearNodeNameIndexOf);
        Assert.notBlank(paperTitleName, "解析小节名称为空");
        // 清洗数据，移除换行符和首尾的空格
        String cleanPaperTitleName = this.cleanTextData(paperTitleName);
        treeNode.setNodeValue(cleanPaperTitleName);
        this.currPaperTitleName = cleanPaperTitleName;

        int endIndex = -1;
        for (WordTemplateTreeNode templateTreeNode : questionTypeTreeNodeList) {
            String questionTypeDesc = templateTreeNode.getNodeName().replace("【", "").replace("】", "");
            QuestionTypeEnum questionTypeEnum = QuestionTypeEnum.byDesc(questionTypeDesc);
            Assert.notNull(questionTypeEnum, "不匹配试题类型，" + questionTypeDesc + "，目前仅支持:{}"
                    + StrUtil.join("|", Arrays.stream(QuestionTypeEnum.values()).map(QuestionTypeEnum::getDesc).collect(Collectors.toList())));
            this.currQuestionTypeEnum = questionTypeEnum;
            // 构建试题小节目录结构
            int indexOf = templateTreeNode.getIndexOf();
            String nodeName = templateTreeNode.getNodeName();
            if (endIndex == -1) {
                endIndex = allQuestionSubText.length();
            }
            int beginIndex = indexOf + nodeName.length();
            String subText = StrUtil.sub(allQuestionSubText, beginIndex, endIndex);
            this.currSubText = subText;
            // 校验试题节点信息
            List<String> questionTypeNameList = questionTypeTreeNodeList.stream().map(WordTemplateTreeNode::getNodeName).collect(Collectors.toList());
            for (String questionTypeName : questionTypeNameList) {
                if (subText.contains(questionTypeName)) {
                    throw new IllegalArgumentException("当前" + templateTreeNode.getNodeName() + "试题类型中，出现重复试题类型节点名称:" + questionTypeName);
                }
            }
            templateTreeNode.setBeginIndex(beginIndex);
            templateTreeNode.setEndIndex(endIndex);
            templateTreeNode.setSubText(subText);

            if (StrUtil.isBlank(subText)) {
                continue;
            }
            Assert.notEmpty(templateTreeNode.getChildrenList(), "模板对象缺失试题结构节点名称，节点标识符:【题目】|【选项】等");
            // 解析试卷小节数据
            this.doParseQuestionData(templateTreeNode);
            endIndex = beginIndex - nodeName.length();
        }
    }

    /**
     * 执行解析试题数据
     *
     * @param treeNode 模板树节点
     */
    private void doParseQuestionData(WordTemplateTreeNode treeNode) {
        // 单个试题类型下所有题目截取文本
        String singleQuestionTypeAllSubText = treeNode.getSubText();
        this.currSubText = singleQuestionTypeAllSubText;
        List<WordTemplateTreeNode> childrenList = treeNode.getChildrenList();
        List<WordTemplateTreeNode> collect = childrenList.stream().filter(n -> StrUtil.isNotBlank(n.getQuestionSplitterStr())).collect(Collectors.toList());
        Assert.notEmpty(collect, "模版对象没有配置试题拆分规则");
        if (collect.size() > 1) {
            throw new RuntimeException("模版对象配置试题拆分规则只能一个，目前存在:" +
                    StrUtil.join("|", collect.stream().map(WordTemplateTreeNode::getNodeName).collect(Collectors.toList())));
        }
        WordTemplateTreeNode templateTreeNode = collect.get(0);
        String nodeName = templateTreeNode.getNodeName();
        List<Integer> splitNodeIndexOfList = new ArrayList<>(16);
        int beginIndex = 0;
        while (true) {
            int indexOf = singleQuestionTypeAllSubText.indexOf(nodeName, beginIndex);
            if (indexOf == -1) {
                break;
            }
            splitNodeIndexOfList.add(indexOf);
            beginIndex = indexOf + nodeName.length();
        }

        Assert.notEmpty(splitNodeIndexOfList, "缺失题与题之间的分割符{}", nodeName);

        // 转换分割符号
        String questionSplitterStr = this.convertQuestionSplitterStr(templateTreeNode.getQuestionSplitterStr());
        // 试题间分割索引位置列表
        List<Integer> questionSpiltIndexOfList = new ArrayList<>(16);
        for (int i = 0; i < splitNodeIndexOfList.size(); i++) {
            Integer beginIndexTemp = splitNodeIndexOfList.get(i);
            Integer endIndexTemp;
            if (i == splitNodeIndexOfList.size() - 1) {
                endIndexTemp = singleQuestionTypeAllSubText.length();
            } else {
                endIndexTemp = splitNodeIndexOfList.get(i + 1);
            }
            // 题目数量大于1的
            if (splitNodeIndexOfList.size() > 1) {
                int indexOf = singleQuestionTypeAllSubText.indexOf(questionSplitterStr, beginIndexTemp);
                if (indexOf == -1) {
                    continue;
                }
                if (indexOf > endIndexTemp) {
                    throw new IllegalArgumentException("解析截取长度大于段落长度");
                }
                questionSpiltIndexOfList.add(indexOf);
            } else {
                // 题目数量等于1
                questionSpiltIndexOfList.add(endIndexTemp);
            }
        }

        // 校验
        Assert.notEmpty(questionSpiltIndexOfList, "根据{}无法拆分多个试题", templateTreeNode.getNodeName());

        // 开始拆分多个试题！！！
        int questionSpiltBeginIndex = 0;
        for (Integer questionSpiltEndIndex : questionSpiltIndexOfList) {
            // 截取试题文本
            String questionText = Assert.notBlank(singleQuestionTypeAllSubText.substring(questionSpiltBeginIndex, questionSpiltEndIndex),
                    "截取试题文本为空，起始位置【{}】，结束位置【{}】", questionSpiltBeginIndex, questionSpiltEndIndex);
            // 校验试题文本, 是否都包含必传节点
            this.checkQuestionText(questionText, childrenList);
            // 拆分一道试题的试题结构
            this.splitQuestionStructure(questionText, childrenList);
            questionSpiltBeginIndex = questionSpiltEndIndex;
        }
    }

    /**
     * 校验试题文本
     *
     * @param questionText         截取的一道试题文本
     * @param templateTreeNodeList 必传的节点列表
     */
    private void checkQuestionText(String questionText, List<WordTemplateTreeNode> templateTreeNodeList) {
        this.currSubText = questionText;
        List<WordTemplateTreeNode> mustList = templateTreeNodeList.stream().filter(WordTemplateTreeNode::isMustStatus).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(mustList)) {
            List<String> mustNodeNameList = mustList.stream().map(WordTemplateTreeNode::getNodeName).collect(Collectors.toList());
            for (String mustNodeName : mustNodeNameList) {
                if (!questionText.contains(mustNodeName)) {
                    throw new IllegalArgumentException("截取试题文本中缺失【" + mustNodeName + "】节点");
                }
                int indexOf = questionText.indexOf(mustNodeName);
                int lastIndexOf = questionText.lastIndexOf(mustNodeName);
                if (indexOf != lastIndexOf) {
                    throw new IllegalArgumentException("存在多个相同的必传节点【" + mustNodeName + "】");
                }
            }
        }
    }

    /**
     * 拆分单个试题的试题结构
     *
     * @param questionText         单个试题文本
     * @param templateTreeNodeList 节点信息列表
     */
    private void splitQuestionStructure(String questionText, List<WordTemplateTreeNode> templateTreeNodeList) {
        this.currSubText = questionText;
        List<WordTemplateTreeNode> questionTitleSplitList = templateTreeNodeList.stream()
                .filter(WordTemplateTreeNode::isQuestionTitleSplitterStatus).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(questionTitleSplitList)) {
            List<WordTemplateTreeNode> list = new ArrayList<>(8);
            for (WordTemplateTreeNode treeNode : questionTitleSplitList) {
                int indexOf = questionText.indexOf(treeNode.getNodeName());
                if (indexOf != -1) {
                    treeNode.setIndexOf(indexOf);
                    treeNode.setSubText(questionText);
                    list.add(treeNode);
                }
            }
            // 校验
            if (CollUtil.isNotEmpty(list) && list.size() > 1) {
                throw new IllegalArgumentException("单个试题里面不能配置多个试题题目分隔符，目前存在多个的是:"
                        + StrUtil.join("|", list.stream().map(WordTemplateTreeNode::getNodeName).collect(Collectors.toList())));
            }
            if (CollUtil.isEmpty(list)) {
                // 解析没有试题题目内容分割符的数据
                this.parseNonQuestionTitleSpiltData(questionText, templateTreeNodeList);
                return;
            }
            WordTemplateTreeNode templateTreeNode = list.get(0);
            String questionTitleSplitterStr = templateTreeNode.getQuestionTitleSplitterStr();
            Assert.notBlank(questionTitleSplitterStr, "节点名称【{}】未配置试题题目内容分割符", templateTreeNode.getNodeName());
            int questionTitleSplitterIndexOf = questionText.indexOf(questionTitleSplitterStr, templateTreeNode.getIndexOf());
            // 校验
            if (questionTitleSplitterIndexOf == -1) {
                throw new IllegalArgumentException("缺失试题题目内容分隔符【" + questionTitleSplitterStr + "】");
            }
            // 兼容富文本标签会出现</span>>>>的情况
            if (">>>".equals(questionTitleSplitterStr) && questionText.indexOf(">>>>", templateTreeNode.getIndexOf()) == questionTitleSplitterIndexOf) {
                questionTitleSplitterIndexOf = questionTitleSplitterIndexOf + 1;
            }
            // 截取背景资料
            String questionTitleSplitterValue = questionText.substring(templateTreeNode.getIndexOf() + templateTreeNode.getNodeName().length(), questionTitleSplitterIndexOf);
            Assert.notBlank(questionTitleSplitterValue, "{}的数值为空", templateTreeNode.getNodeName());
            String cleanQuestionTitleSplitterValue = this.cleanTextData(questionTitleSplitterValue);
            Assert.notBlank(cleanQuestionTitleSplitterValue, "{}清洗后的数值为空", templateTreeNode.getNodeName());
            this.currQuestionTitleSplitterValue = cleanQuestionTitleSplitterValue;

            // 截取没有背景资料的试题内容文本
            String subText = questionText.substring(questionTitleSplitterIndexOf + questionTitleSplitterStr.length());
            Assert.notBlank(subText, "截取试题其他内容文本为空");
            // 解析没有试题题目内容分割符的数据
            this.parseNonQuestionTitleSpiltData(subText, templateTreeNodeList);
        } else {
            // 解析没有试题题目内容分割符的数据
            this.parseNonQuestionTitleSpiltData(questionText, templateTreeNodeList);
        }
        this.currQuestionTitleSplitterValue = "";
    }

    /**
     * 解析没有试题标题题目分隔符的数据
     *
     * @param questionText         试题文本字符串
     * @param templateTreeNodeList 模板树节点列表
     */
    private void parseNonQuestionTitleSpiltData(String questionText, List<WordTemplateTreeNode> templateTreeNodeList) {
        this.currSubText = questionText;
        // 获取最近的匹配的节点名称索引位置
        int nearestIndexOf = this.getNearestIndexOf(questionText, templateTreeNodeList);

        // 截取的题目标题中有可能包含着选项
        String questionTitleOrOptionStr = Assert.notBlank(questionText.substring(0, nearestIndexOf), "截取的题目标题内容为空");
//        this.currSubText = questionTitleOrOptionStr;
        Optional<WordTemplateTreeNode> questionTitleOptional = templateTreeNodeList.stream().filter(n -> "【题目】".equals(n.getNodeName())).findFirst();
        if (!questionTitleOptional.isPresent()) {
            throw new IllegalArgumentException("模板没有配置【题目】节点");
        }
        WordTemplateTreeNode questionTitleTreeNode = questionTitleOptional.get();
        Optional<WordTemplateTreeNode> questionOptionOptional = templateTreeNodeList.stream().filter(n -> "【选项】".equals(n.getNodeName())).findFirst();
        if (!questionOptionOptional.isPresent()) {
            throw new IllegalArgumentException("模板没有配置【选项】节点");
        }
        // 封装题目对象
        WordImportQuestionData wordImportQuestionData = new WordImportQuestionData();
        wordImportQuestionData.setPaperName(Assert.notBlank(this.currPaperName, "获取试卷名称为空"));
        wordImportQuestionData.setPaperTitleName(Assert.notBlank(this.currPaperTitleName, "获取试卷小节名称为空"));
        Assert.notNull(this.currQuestionTypeEnum, "获取试题类型枚举为空");
        wordImportQuestionData.setQuestionType(this.currQuestionTypeEnum.getCode());
        wordImportQuestionData.setQuestionTypeDesc(this.currQuestionTypeEnum.getDesc());
        wordImportQuestionData.setTitleBackground(this.currQuestionTitleSplitterValue);
        WordTemplateTreeNode questionOptionTreeNode = questionOptionOptional.get();
        String questionTitleStr;
        // 判断是否存在选项
        int optionIndexOf = questionTitleOrOptionStr.indexOf("\nA.");
        if (optionIndexOf == -1) {
            if (this.isOptionQuestion()) {
                throw new IllegalArgumentException("当前题目类型为" + this.currQuestionTypeEnum.getDesc() + "缺失选项值");
            }
            questionTitleTreeNode.setNodeValue(questionTitleOrOptionStr);
            questionTitleStr = questionTitleOrOptionStr;
        } else {
            if (!this.isOptionQuestion()) {
                throw new IllegalArgumentException("当前题目类型为" + this.currQuestionTypeEnum.getDesc() + "不应该有选项值");
            }
            questionTitleStr = questionTitleOrOptionStr.substring(0, optionIndexOf);
            questionTitleTreeNode.setNodeValue(questionTitleStr);
            // 分割试题选项数据结构
            List<WordImportQuestionData.OptionData> optionDataList = this.splitQuestionOptionStructure(questionTitleOrOptionStr.substring(optionIndexOf));
            this.currOptionDataList = optionDataList;
            Assert.notEmpty(optionDataList, "当前题目类型为{}，缺少必要的选项信息", this.currQuestionTypeEnum.getDesc());
            // 判断重复选项值
            List<String> distinctList = optionDataList.stream().map(WordImportQuestionData.OptionData::getContent).distinct().collect(Collectors.toList());
            if (distinctList.size() != optionDataList.size()) {
                throw new IllegalArgumentException("出现重复选项");
            }
            String optionDataJsonStr = JSON.toJSONString(optionDataList);
            questionOptionTreeNode.setNodeValue(optionDataJsonStr);
            wordImportQuestionData.setOptionDataList(optionDataList);
        }
        // 清洗数据
        String cleanQuestionTitleStr = this.cleanTextData(questionTitleStr);
        Assert.notBlank(cleanQuestionTitleStr, "清洗后的题目标题内容为空");
        wordImportQuestionData.setQuestionTitle(cleanQuestionTitleStr);

        // 解析试题文本其他节点信息
        this.parseQuestionOtherNodeStructure(questionText, templateTreeNodeList, nearestIndexOf, wordImportQuestionData);
        this.currOptionDataList = null;
    }

    /**
     * 判断是否要有选项的试题类型
     *
     * @return 是否
     */
    private boolean isOptionQuestion() {
        // 单选题和多选题是必须要有选项的
        if (this.currQuestionTypeEnum == QuestionTypeEnum.SINGLE_CHOICE
                || this.currQuestionTypeEnum == QuestionTypeEnum.MULTIPLE_CHOICE) {
            return true;
        }
        return false;
    }

    /**
     * 获取最接近的节点索引位置
     *
     * @param questionText         试题文本字符串
     * @param templateTreeNodeList 模板树节点列表
     * @return 最接近的节点索引位置
     */
    private int getNearestIndexOf(String questionText, List<WordTemplateTreeNode> templateTreeNodeList) {
        List<String> nodeNameList = templateTreeNodeList.stream().map(WordTemplateTreeNode::getNodeName).collect(Collectors.toList());
        // 最近的匹配的节点名称索引位置
        int nearestIndexOf = -1;
        for (String nodeName : nodeNameList) {
            int indexOf = questionText.indexOf(nodeName);
            if (indexOf != -1 && nearestIndexOf == -1) {
                nearestIndexOf = indexOf;
            }
            if (indexOf != -1 && indexOf < nearestIndexOf) {
                nearestIndexOf = indexOf;
            }
        }
        // 校验
        if (nearestIndexOf == -1) {
            throw new IllegalArgumentException("未找到试题题目的分割符号");
        }
        if (nearestIndexOf == 0) {
            throw new IllegalArgumentException("试题文本首位不应该出现节点名称");
        }
        return nearestIndexOf;
    }

    /**
     * 解析试题文本中其他节点结构数据
     *
     * @param questionText           试题文本字符串
     * @param templateTreeNodeList   模板树节点列表
     * @param nearestIndexOf         最近的树节点索引位置
     * @param wordImportQuestionData 响应对象
     */
    private void parseQuestionOtherNodeStructure(String questionText, List<WordTemplateTreeNode> templateTreeNodeList,
                                                 int nearestIndexOf, WordImportQuestionData wordImportQuestionData) {
        // 获取试题其他结构截取文本
        String questionOtherStructureSubText = questionText.substring(nearestIndexOf);
//        this.currSubText = questionOtherStructureSubText;
        // 解析其他节点数据
        List<WordTemplateTreeNode> collectList = templateTreeNodeList.stream().filter(n ->
                StrUtil.isBlank(n.getQuestionTitleSplitterStr()) && !"【题目】".equals(n.getNodeName()) && !"【选项】".equals(n.getNodeName())
        ).collect(Collectors.toList());
        Map<Integer, String> map = new TreeMap<>();
        for (WordTemplateTreeNode otherTemplateTreeNode : collectList) {
            String otherNodeName = otherTemplateTreeNode.getNodeName();
            int indexOf = questionOtherStructureSubText.indexOf(otherNodeName);
            if (indexOf != -1) {
                map.put(indexOf, otherNodeName);
            }
        }
        if (CollUtil.isEmpty(map)) {
            throw new IllegalArgumentException("缺少试题节点名称");
        }

        // 遍历，解析选项
        List<Integer> indexOfList = new ArrayList<>(map.keySet());
        for (int i = 0; i < indexOfList.size(); i++) {
            Integer beginIndexOf = indexOfList.get(i);
            String otherNodeName = map.get(beginIndexOf);
            Integer endIndexOf;
            if (i == indexOfList.size() - 1) {
                endIndexOf = questionOtherStructureSubText.length();
            } else {
                endIndexOf = indexOfList.get(i + 1);
            }
            String otherNodeValue = questionOtherStructureSubText.substring(beginIndexOf + otherNodeName.length(), endIndexOf);
            Assert.notBlank(otherNodeValue, "解析{}节点值为空", otherNodeName);
            String cleanOtherNodeValue = this.cleanTextData(otherNodeValue);
            Assert.notBlank(otherNodeValue, "清洗{}换行和首尾去空格后节点值为空", otherNodeName);
            // 获取对应的树节点对象
            Optional<WordTemplateTreeNode> firstOptional = templateTreeNodeList.stream().filter(n -> n.getNodeName().equals(otherNodeName)).findFirst();
            if (!firstOptional.isPresent()) {
                throw new IllegalArgumentException("节点" + otherNodeName + "不存在");
            }
            WordTemplateTreeNode templateTreeNode = firstOptional.get();
            templateTreeNode.setNodeValue(cleanOtherNodeValue);
            if ("【分数】".equals(otherNodeName)) {
                if (!NumberUtil.isNumber(cleanOtherNodeValue)) {
                    throw new IllegalArgumentException(otherNodeName + "的数值为 " + cleanOtherNodeValue + " 不是标准的数字，可能存在隐藏样式，可尝试用格式刷处理一下");
                }
                wordImportQuestionData.setScore(Double.valueOf(cleanOtherNodeValue));
            }
            if ("【答案】".equals(otherNodeName)) {
                // 校验单选题的答案只能为纯字母
                if (this.currQuestionTypeEnum == QuestionTypeEnum.SINGLE_CHOICE) {
                    if (cleanOtherNodeValue.length() > 1) {
                        throw new IllegalArgumentException("当前题目为单选题，答案只能是单一的纯字母");
                    }
                    if (!Validator.isUpperCase(cleanOtherNodeValue)) {
                        throw new IllegalArgumentException("当前题目为单选题，答案只能是单一的大写字母");
                    }
                }
                // 校验多选题答案必须为两个及以上纯字母
                else if (this.currQuestionTypeEnum == QuestionTypeEnum.MULTIPLE_CHOICE) {
                    if (cleanOtherNodeValue.length() < 2) {
                        throw new IllegalArgumentException("当前题目为多选题，答案必须是两个及以上的大写字母");
                    }
                    if (!Validator.isUpperCase(cleanOtherNodeValue)) {
                        throw new IllegalArgumentException("当前题目为多选题，答案只能是两个及以上的大写字母，不能有其他符号");
                    }
                    if (cleanOtherNodeValue.length() > this.currOptionDataList.size()) {
                        throw new IllegalArgumentException("当前题目为多选题，答案总数不能超过选项总数");
                    }
                }
                wordImportQuestionData.setQuestionAnswer(cleanOtherNodeValue);
            }
            if ("【解析】".equals(otherNodeName)) {
                wordImportQuestionData.setQuestionAnalysis(cleanOtherNodeValue);
            }
        }
        wordImportQuestionData.setSort(this.sort);
        this.LIST.add(wordImportQuestionData);
        this.sort++;
    }

    /**
     * 分割试题选项数据结构
     *
     * @param optionText 选项文本
     * @return 选项数据列表
     */
    private List<WordImportQuestionData.OptionData> splitQuestionOptionStructure(String optionText) {
//        this.currSubText = optionText;
        List<WordImportQuestionData.OptionData> optionDataList = new ArrayList<>(8);
        Map<Integer, String> map = new TreeMap<>();
        for (String optionLetterName : OPTION_LETTER_ARR) {
            int indexOf = optionText.indexOf(optionLetterName);
            if (indexOf != -1) {
                map.put(indexOf, optionLetterName);
            }
        }
        Assert.notEmpty(map, "缺少选项字母");

        // 遍历，解析选项
        List<Integer> indexOfList = new ArrayList<>(map.keySet());
        for (int i = 0; i < indexOfList.size(); i++) {
            Integer beginIndexOf = indexOfList.get(i);
            String optionLetterName = map.get(beginIndexOf);
            Integer endIndexOf;
            if (i == indexOfList.size() - 1) {
                endIndexOf = optionText.length();
            } else {
                endIndexOf = indexOfList.get(i + 1);
            }
            // 解析封装选项数据对象
            WordImportQuestionData.OptionData optionData = this.doSplitQuestionOptionStructure(optionText, beginIndexOf, endIndexOf, optionLetterName);
            optionDataList.add(optionData);
        }
        return optionDataList;
    }

    /**
     * 解析封装选项数据对象
     *
     * @param optionText       多个选项截取文本
     * @param beginIndexOf     单个选项开始索引位置
     * @param endIndexOf       单个选项结束索引位置
     * @param optionLetterName 当前选项字母检索字符串名称
     * @return 选项数据对象
     */
    private WordImportQuestionData.OptionData doSplitQuestionOptionStructure(String optionText, Integer beginIndexOf, Integer endIndexOf, String optionLetterName) {
        String singleOptionText = optionText.substring(beginIndexOf, endIndexOf);
//        this.currSubText = singleOptionText;
        Assert.notBlank(singleOptionText, "单个选项缺少内容");
        String optionContentValue = singleOptionText.replace(optionLetterName, "");
        Assert.notBlank(optionContentValue, "单个选项缺少内容！");
        String optionLetter = optionLetterName.replaceAll("\n", "").replace(".", "");
        Assert.notBlank(optionLetter, "单个选项缺少字母");
        // 构建选项对象
        WordImportQuestionData.OptionData optionData = new WordImportQuestionData.OptionData();
        String cleanOptionContentValue = this.cleanTextData(optionContentValue);
        Assert.notBlank("清洗后的选项文本为空");
        optionData.setContent(cleanOptionContentValue);
        optionData.setLetter(optionLetter);
        return optionData;
    }

    /**
     * 清洗文本数据，主要清除换行符和文本首尾的空格
     *
     * @param text 文本字符串
     * @return 清洗后的文本
     */
    private String cleanTextData(String text) {
        if (text == null) {
            return "";
        }
//        return text.replaceAll("\n", "").trim();
        return text.trim();
    }

    /**
     * 转换试题分割符号
     *
     * @param questionSplitterStr 配置的试题分割符号
     * @return 转换后的试题分割符号
     */
    private String convertQuestionSplitterStr(String questionSplitterStr) {
        if ("\\n\\n".equals(questionSplitterStr)) {
            questionSplitterStr = "\n\n";
        }
        return questionSplitterStr;
    }

}
